package org.dromara.common.mybatis.config

import cn.hutool.core.net.NetUtil
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler
import com.baomidou.mybatisplus.core.handlers.PostInitTableInfoHandler
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor
import org.dromara.common.core.factory.YmlPropertySourceFactory
import org.dromara.common.core.utils.SpringUtils.getBean
import org.dromara.common.mybatis.aspect.DataPermissionPointcutAdvisor
import org.dromara.common.mybatis.handler.InjectionMetaObjectHandler
import org.dromara.common.mybatis.handler.MybatisExceptionHandler
import org.dromara.common.mybatis.handler.PlusPostInitTableInfoHandler
import org.dromara.common.mybatis.interceptor.PlusDataPermissionInterceptor
import org.mybatis.spring.annotation.MapperScan
import org.springframework.beans.BeansException
import org.springframework.beans.factory.config.BeanDefinition
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.PropertySource
import org.springframework.context.annotation.Role
import org.springframework.transaction.annotation.EnableTransactionManagement

/**
 * mybatis-plus配置类(下方注释有插件介绍)
 *
 * @author Lion Li
 * @updater LikeYouDo
 * @date 2025/1/26 1:09
 */
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@EnableTransactionManagement(proxyTargetClass = true)
@MapperScan("\${mybatis-plus.mapperPackage}")
@PropertySource(value = ["classpath:common-mybatis.yml"], factory = YmlPropertySourceFactory::class)
open class MybatisPlusConfig {
    @Bean
    fun mybatisPlusInterceptor(): MybatisPlusInterceptor {
        val interceptor = MybatisPlusInterceptor()
        // 多租户插件 必须放到第一位
        try {
            val tenant = getBean(TenantLineInnerInterceptor::class.java)
            interceptor.addInnerInterceptor(tenant)
        } catch (ignore: BeansException) {
        }
        // 数据权限处理
        interceptor.addInnerInterceptor(dataPermissionInterceptor())
        // 分页插件
        interceptor.addInnerInterceptor(paginationInnerInterceptor())
        // 乐观锁插件
        interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor())
        return interceptor
    }

    /**
     * 数据权限拦截器
     */
    fun dataPermissionInterceptor(): PlusDataPermissionInterceptor {
        return PlusDataPermissionInterceptor()
    }

    /**
     * 数据权限切面处理器
     */
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    fun dataPermissionPointcutAdvisor(): DataPermissionPointcutAdvisor {
        return DataPermissionPointcutAdvisor()
    }

    /**
     * 分页插件，自动识别数据库类型
     */
    fun paginationInnerInterceptor(): PaginationInnerInterceptor {
        val paginationInnerInterceptor = PaginationInnerInterceptor()
        // 分页合理化
        paginationInnerInterceptor.isOverflow = true
        return paginationInnerInterceptor
    }

    /**
     * 乐观锁插件
     */
    fun optimisticLockerInnerInterceptor(): OptimisticLockerInnerInterceptor {
        return OptimisticLockerInnerInterceptor()
    }

    /**
     * 元对象字段填充控制器
     */
    @Bean
    fun metaObjectHandler(): MetaObjectHandler {
        return InjectionMetaObjectHandler()
    }

    /**
     * 使用网卡信息绑定雪花生成器
     * 防止集群雪花ID重复
     */
    @Bean
    fun idGenerator(): IdentifierGenerator {
        return DefaultIdentifierGenerator(NetUtil.getLocalhost())
    }

    /**
     * 异常处理器
     */
    @Bean
    fun mybatisExceptionHandler(): MybatisExceptionHandler {
        return MybatisExceptionHandler()
    }

    /**
     * 初始化表对象处理器
     */
    @Bean
    fun postInitTableInfoHandler(): PostInitTableInfoHandler {
        return PlusPostInitTableInfoHandler()
    }

    /**
     * PaginationInnerInterceptor 分页插件，自动识别数据库类型
     * https://baomidou.com/pages/97710a/
     * OptimisticLockerInnerInterceptor 乐观锁插件
     * https://baomidou.com/pages/0d93c0/
     * MetaObjectHandler 元对象字段填充控制器
     * https://baomidou.com/pages/4c6bcf/
     * ISqlInjector sql注入器
     * https://baomidou.com/pages/42ea4a/
     * BlockAttackInnerInterceptor 如果是对全表的删除或更新操作，就会终止该操作
     * https://baomidou.com/pages/f9a237/
     * IllegalSQLInnerInterceptor sql性能规范插件(垃圾SQL拦截)
     * IdentifierGenerator 自定义主键策略
     * https://baomidou.com/pages/568eb2/
     * TenantLineInnerInterceptor 多租户插件
     * https://baomidou.com/pages/aef2f2/
     * DynamicTableNameInnerInterceptor 动态表名插件
     * https://baomidou.com/pages/2a45ff/
     */

}
